/*******************************************************************************
* Copyright (c) 2000, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.dnd;
import org.eclipse.swt.*;
import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.motif.*;
import org.eclipse.swt.widgets.*;
class ClipboardProxy {
Display display;
int shellHandle;
int atomAtom, clipboardAtom, motifClipboardAtom, primaryAtom, targetsAtom;
int[][] convertData = new int[10][3];
Clipboard activeClipboard = null;
Clipboard activePrimaryClipboard = null;
Object[] clipboardData;
Transfer[] clipboardDataTypes;
Object[] primaryClipboardData;
Transfer[] primaryClipboardDataTypes;
boolean done = false;
Object selectionValue;
Transfer selectionTransfer;
Callback XtConvertSelectionCallback;
Callback XtLoseSelectionCallback;
Callback XtSelectionDoneCallback;
Callback XtSelectionCallbackCallback;
static byte [] ATOM = Converter.wcsToMbcs (null, "ATOM", true); //$NON-NLS-1$
static byte [] CLIPBOARD = Converter.wcsToMbcs (null, "CLIPBOARD", true); //$NON-NLS-1$
static byte [] PRIMARY = Converter.wcsToMbcs (null, "PRIMARY", true); //$NON-NLS-1$
static byte [] TARGETS = Converter.wcsToMbcs (null, "TARGETS", true); //$NON-NLS-1$
static byte [] _MOTIF_CLIPBOARD_TARGETS = Converter.wcsToMbcs (null, "_MOTIF_CLIPBOARD_TARGETS", true); //$NON-NLS-1$
static String ID = "CLIPBOARD PROXY OBJECT"; //$NON-NLS-1$
static ClipboardProxy _getInstance(final Display display) {
ClipboardProxy proxy = (ClipboardProxy) display.getData(ID);
if (proxy != null) return proxy;
proxy = new ClipboardProxy(display);
display.setData(ID, proxy);
display.addListener(SWT.Dispose, new Listener() {
public void handleEvent(Event event) {
ClipboardProxy clipbordProxy = (ClipboardProxy)display.getData(ID);
if (clipbordProxy == null) return;
display.setData(ID, null);
clipbordProxy.dispose();
}
});
return proxy;
}
ClipboardProxy(Display display) {
this.display = display;
XtConvertSelectionCallback = new Callback(this, "XtConvertSelection", 7); //$NON-NLS-1$
if (XtConvertSelectionCallback.getAddress() == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
XtLoseSelectionCallback = new Callback(this, "XtLoseSelection", 2); //$NON-NLS-1$
if (XtLoseSelectionCallback.getAddress() == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
XtSelectionDoneCallback = new Callback(this, "XtSelectionDone", 3); //$NON-NLS-1$
if (XtSelectionDoneCallback.getAddress() == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
XtSelectionCallbackCallback = new Callback(this, "XtSelectionCallback", 7); //$NON-NLS-1$
if (XtSelectionCallbackCallback.getAddress() == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
int widgetClass = OS.topLevelShellWidgetClass ();
shellHandle = OS.XtAppCreateShell (null, null, widgetClass, display.xDisplay, null, 0);
OS.XtSetMappedWhenManaged (shellHandle, false);
OS.XtRealizeWidget (shellHandle);
int xDisplay = OS.XtDisplay(shellHandle);
atomAtom = OS.XmInternAtom(xDisplay, ATOM, true);
clipboardAtom = OS.XmInternAtom(xDisplay, CLIPBOARD, true);
motifClipboardAtom = OS.XmInternAtom(xDisplay, _MOTIF_CLIPBOARD_TARGETS, true);
primaryAtom = OS.XmInternAtom(xDisplay, PRIMARY, true);
targetsAtom = OS.XmInternAtom(xDisplay, TARGETS, true);
}
void clear(Clipboard owner, int clipboards) {
int xDisplay = OS.XtDisplay(shellHandle);
if (xDisplay == 0) return;
if ((clipboards & DND.CLIPBOARD) != 0 && activeClipboard == owner) {
OS.XtDisownSelection(shellHandle, clipboardAtom, OS.CurrentTime);
}
if ((clipboards & DND.SELECTION_CLIPBOARD) != 0 && activePrimaryClipboard == owner) {
OS.XtDisownSelection(shellHandle, primaryAtom, OS.CurrentTime);
}
}
void dispose () {
if (display == null) return;
if (shellHandle != 0) {
OS.XtDestroyWidget (shellHandle);
shellHandle = 0;
}
if (XtConvertSelectionCallback != null) XtConvertSelectionCallback.dispose();
XtConvertSelectionCallback = null;
if (XtLoseSelectionCallback != null) XtLoseSelectionCallback.dispose();
XtLoseSelectionCallback = null;
if (XtSelectionCallbackCallback != null) XtSelectionCallbackCallback.dispose();
XtSelectionCallbackCallback = null;
if (XtSelectionDoneCallback != null) XtSelectionDoneCallback.dispose();
XtSelectionDoneCallback = null;
activeClipboard = null;
activePrimaryClipboard = null;
clipboardData = null;
clipboardDataTypes = null;
primaryClipboardData = null;
primaryClipboardDataTypes = null;
}
Object getContents(Transfer transfer, int clipboardType) {
int[] types = getAvailableTypes(clipboardType);
int index = -1;
TransferData transferData = new TransferData();
for (int i = 0; i < types.length; i++) {
transferData.type = types[i];
if (transfer.isSupportedType(transferData)) {
index = i;
break;
}
}
if (index == -1) return null;
done = false;
selectionValue = null; selectionTransfer = transfer;
int selection = clipboardType == DND.CLIPBOARD ? clipboardAtom : primaryAtom;
OS.XtGetSelectionValue(shellHandle, selection, types[index], XtSelectionCallbackCallback.getAddress(), 0, OS.CurrentTime);
if (!done) {
int xDisplay = OS.XtDisplay (shellHandle);
if (xDisplay == 0) return null;
int xtContext = OS.XtDisplayToApplicationContext(xDisplay);
int selectionTimeout = OS.XtAppGetSelectionTimeout(xtContext);
wait(selectionTimeout);
}
return (!done) ? null : selectionValue;
}
int[] getAvailableTypes(int clipboardType) {
int xDisplay = OS.XtDisplay (shellHandle);
if (xDisplay == 0) return new int[0];
done = false;
selectionValue = null; selectionTransfer = null;
int selection = clipboardType == DND.CLIPBOARD ? clipboardAtom : primaryAtom;
int target = targetsAtom;
OS.XtGetSelectionValue(shellHandle, selection, target, XtSelectionCallbackCallback.getAddress(), 0, OS.CurrentTime);
if (!done) {
int xtContext = OS.XtDisplayToApplicationContext(xDisplay);
int selectionTimeout = OS.XtAppGetSelectionTimeout(xtContext);
wait(selectionTimeout);
}
if (done && selectionValue == null) {
done = false;
target = motifClipboardAtom;
OS.XtGetSelectionValue(shellHandle, selection, target, XtSelectionCallbackCallback.getAddress(), 0, OS.CurrentTime);
if (!done) {
int xtContext = OS.XtDisplayToApplicationContext(xDisplay);
int selectionTimeout = OS.XtAppGetSelectionTimeout(xtContext);
wait(selectionTimeout);
}
}
if (done && selectionValue == null) {
done = false;
target = atomAtom;
OS.XtGetSelectionValue(shellHandle, selection, target, XtSelectionCallbackCallback.getAddress(), 0, OS.CurrentTime);
if (!done) {
int xtContext = OS.XtDisplayToApplicationContext(xDisplay);
int selectionTimeout = OS.XtAppGetSelectionTimeout(xtContext);
wait(selectionTimeout);
}
}
return (!done || selectionValue == null) ? new int[0] : (int[])selectionValue;
}
void setContents(Clipboard owner, Object[] data, Transfer[] dataTypes, int clipboards) {
if ((clipboards & DND.CLIPBOARD) != 0) {
clipboardData = data;
clipboardDataTypes = dataTypes;
int XtConvertSelectionProc = XtConvertSelectionCallback.getAddress();
int XtLoseSelectionProc = XtLoseSelectionCallback.getAddress();
int XtSelectionDoneProc = XtSelectionDoneCallback.getAddress();
if (!OS.XtOwnSelection(shellHandle, clipboardAtom, OS.CurrentTime, XtConvertSelectionProc, XtLoseSelectionProc, XtSelectionDoneProc)) {
DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
}
activeClipboard = owner;
}
if ((clipboards & DND.SELECTION_CLIPBOARD) != 0) {
primaryClipboardData = data;
primaryClipboardDataTypes = dataTypes;
int XtConvertSelectionProc = XtConvertSelectionCallback.getAddress();
int XtLoseSelectionProc = XtLoseSelectionCallback.getAddress();
int XtSelectionDoneProc = XtSelectionDoneCallback.getAddress();
if (!OS.XtOwnSelection(shellHandle, primaryAtom, OS.CurrentTime, XtConvertSelectionProc, XtLoseSelectionProc, XtSelectionDoneProc)) {
DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
}
activePrimaryClipboard = owner;
}
}
void storePtr(int ptr, int selection, int target) {
int index = -1;
for (int i = 0; i < convertData.length; i++) {
if (convertData[i][0] == 0){
index = i;
break;
}
}
if (index == -1) {
int[][] newConvertData = new int[convertData.length + 4][3];
System.arraycopy(convertData, 0, newConvertData, 0, convertData.length);
index = convertData.length;
convertData = newConvertData;
}
convertData[index][0] = selection;
convertData[index][1] = target;
convertData[index][2] = ptr;
}
void wait(int timeout) {
int xDisplay = OS.XtDisplay(shellHandle);
if (xDisplay == 0) return;
long start = System.currentTimeMillis();
Callback checkEventCallback = new Callback(this, "checkEvent", 3); //$NON-NLS-1$
int checkEventProc = checkEventCallback.getAddress();
if (checkEventProc == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
int xEvent = OS.XtMalloc (XEvent.sizeof);
display.timerExec(timeout, new Runnable() {
public void run() {
// timer required to force display.sleep() to wake up
// in the case where no events are received
}
});
while (!done && System.currentTimeMillis() - start < timeout && display != null) {
if (OS.XCheckIfEvent (xDisplay, xEvent, checkEventProc, 0) != 0) {
OS.XtDispatchEvent(xEvent);
} else {
display.sleep();
}
}
OS.XtFree (xEvent);
checkEventCallback.dispose();
}
int checkEvent(int display, int event, int arg) {
XEvent xEvent = new XEvent();
OS.memmove (xEvent, event, XEvent.sizeof);
switch (xEvent.type) {
case OS.SelectionClear:
case OS.SelectionNotify:
case OS.SelectionRequest:
case OS.PropertyNotify:
return 1;
}
return 0;
}
int XtConvertSelection(int widget, int selection, int target, int type, int value, int length, int format) {
int selectionAtom = 0;
if (selection != 0) {
int[] dest = new int[1];
OS.memmove(dest, selection, 4);
selectionAtom = dest[0];
}
if (selectionAtom == 0) return 0;
Transfer[] types = null;
if (selectionAtom == clipboardAtom) types = clipboardDataTypes;
if (selectionAtom == primaryAtom) types = primaryClipboardDataTypes;
if (types == null) return 0;
int targetAtom = 0;
if (target != 0) {
int[] dest = new int[1];
OS.memmove(dest, target, 4);
targetAtom = dest[0];
}
if (targetAtom == atomAtom ||
targetAtom == targetsAtom ||
targetAtom == motifClipboardAtom) {
int[] transferTypes = new int[] {targetAtom};
for (int i = 0; i < types.length; i++) {
TransferData[] subTypes = types[i].getSupportedTypes();
int[] newtransferTypes = new int[transferTypes.length + subTypes.length];
System.arraycopy(transferTypes, 0, newtransferTypes, 0, transferTypes.length);
int index = transferTypes.length;
transferTypes = newtransferTypes;
for (int j = 0; j < subTypes.length; j++) {
transferTypes[index++] = subTypes[j].type;
}
}
int ptr = OS.XtMalloc(transferTypes.length*4);
storePtr(ptr, selectionAtom, targetAtom);
OS.memmove(ptr, transferTypes, transferTypes.length*4);
OS.memmove(type, new int[]{targetAtom}, 4);
OS.memmove(value, new int[] {ptr}, 4);
OS.memmove(length, new int[]{transferTypes.length}, 4);
OS.memmove(format, new int[]{32}, 4);
return 1;
}
TransferData tdata = new TransferData();
tdata.type = targetAtom;
int index = -1;
for (int i = 0; i < types.length; i++) {
if (types[i].isSupportedType(tdata)) {
index = i;
break;
}
}
if (index == -1) return 0;
Object[] data = selectionAtom == clipboardAtom ? clipboardData : primaryClipboardData;
types[index].javaToNative(data[index], tdata);
if (tdata.format < 8 || tdata.format % 8 != 0) {
OS.XtFree(tdata.pValue);
return 0;
}
// copy data back to value
OS.memmove(type, new int[]{tdata.type}, 4);
OS.memmove(value, new int[]{tdata.pValue}, 4);
OS.memmove(length, new int[]{tdata.length}, 4);
OS.memmove(format, new int[]{tdata.format}, 4);
storePtr(tdata.pValue, selectionAtom, targetAtom);
return 1;
}
int XtLoseSelection(int widget, int selection) {
if (selection == clipboardAtom) {
activeClipboard = null;
clipboardData = null;
clipboardDataTypes = null;
}
if (selection == primaryAtom) {
activePrimaryClipboard = null;
primaryClipboardData = null;
primaryClipboardDataTypes = null;
}
return 0;
}
int XtSelectionCallback(int widget, int client_data, int selection, int type, int value, int length, int format) {
done = true;
int[] selectionType = new int[1];
if (type != 0) OS.memmove(selectionType, type, 4);
if (selectionType[0] == 0) return 0;
int[] selectionLength = new int[1];
if (length != 0) OS.memmove(selectionLength, length, 4);
if (selectionLength[0] == 0) return 0;
int[] selectionFormat = new int[1];
if (format != 0) OS.memmove(selectionFormat, format, 4);
if (selectionType[0] == atomAtom ||
selectionType[0] == targetsAtom ||
selectionType[0] == motifClipboardAtom) {
int[] targets = new int[selectionLength[0]];
OS.memmove(targets, value, selectionLength[0] * selectionFormat [0] / 8);
selectionValue = targets;
return 0;
}
if (selectionTransfer != null) {
TransferData transferData = new TransferData();
transferData.type = selectionType[0];
transferData.length = selectionLength[0];
transferData.format = selectionFormat[0];
transferData.pValue = value;
transferData.result = 1;
selectionValue = selectionTransfer.nativeToJava(transferData);
}
return 0;
}
int XtSelectionDone(int widget, int selection, int target) {
if (target == 0 || selection == 0) return 0;
int[] selectionAtom = new int[1];
OS.memmove(selectionAtom, selection, 4);
int[] targetAtom = new int[1];
OS.memmove(targetAtom, target, 4);
for (int i = 0; i < convertData.length; i++) {
if (convertData[i][0] == selectionAtom[0] && convertData[i][1] == targetAtom[0]) {
OS.XtFree(convertData[i][2]);
convertData[i][0] = convertData[i][1] = convertData[i][2] = 0;
break;
}
}
return 0;
}
}